#include "log_module.h"
#include "eeprom_driver.h"
#include <string.h>

static log_config_t *log_config = RT_NULL;
static rt_thread_t log_thread = RT_NULL;
static rt_mutex_t log_mutex = RT_NULL;

/* Log buffer in RAM */
static log_entry_t log_buffer[1000];
static uint32_t log_buffer_size = 1000;

static const char *log_level_strings[] = {
    "INFO",
    "WARNING", 
    "ERROR",
    "ALARM",
    "OPERATION",
    "DEBUG"
};

static const char *module_strings[] = {
    "MAIN",
    "IO",
    "ADC",
    "TEMP",
    "FLOW",
    "WATER",
    "VALVE",
    "PID",
    "ALARM",
    "LOG",
    "EEPROM",
    "MODBUS"
};

static rt_err_t log_store_to_eeprom(void)
{
    rt_err_t result;
    uint32_t start_index, count;
    
    if (!log_config->enable_storage) {
        return RT_OK;
    }
    
    /* Calculate range to store */
    if (log_config->wrap_around) {
        /* Circular buffer, store all entries */
        start_index = 0;
        count = log_buffer_size;
    } else {
        /* Linear buffer, store from beginning */
        start_index = 0;
        count = log_config->current_index;
    }
    
    /* Store to EEPROM */
    result = eeprom_write(0x1000, (uint8_t*)log_buffer, count * sizeof(log_entry_t));
    if (result != RT_OK) {
        LOG_E("Failed to store logs to EEPROM\n");
        return result;
    }
    
    LOG_I("Stored %d log entries to EEPROM\n", count);
    
    return RT_OK;
}

static rt_err_t log_load_from_eeprom(void)
{
    rt_err_t result;
    uint32_t count;
    
    /* Try to load logs from EEPROM */
    result = eeprom_read(0x1000, (uint8_t*)log_buffer, log_buffer_size * sizeof(log_entry_t));
    if (result != RT_OK) {
        LOG_W("Failed to load logs from EEPROM\n");
        return result;
    }
    
    /* Find the last valid entry */
    count = 0;
    for (uint32_t i = 0; i < log_buffer_size; i++) {
        if (log_buffer[i].timestamp == 0) {
            break;
        }
        count++;
    }
    
    log_config->current_index = count;
    log_config->wrap_around = RT_FALSE;
    
    LOG_I("Loaded %d log entries from EEPROM\n", count);
    
    return RT_OK;
}

static void process_log_message(message_t *msg)
{
    if (msg == RT_NULL) return;
    
    switch (msg->msg_type) {
        case MSG_LOG_RECORD:
            if (msg->data != RT_NULL && msg->data_len == sizeof(log_entry_t)) {
                log_entry_t *entry = (log_entry_t *)msg->data;
                log_write(entry->level, entry->module, entry->message, entry->data_value);
            }
            break;
            
        case MSG_ALARM_TRIGGER:
            if (msg->data != RT_NULL && msg->data_len == sizeof(alarm_info_t)) {
                alarm_info_t *alarm = (alarm_info_t *)msg->data;
                char message[64];
                rt_snprintf(message, sizeof(message), "Alarm triggered: type=%d, value=%.1f", 
                           alarm->type, alarm->value);
                log_write(LOG_ALARM, MODULE_ALARM, message, alarm->value);
            }
            break;
            
        default:
            break;
    }
}

rt_err_t log_module_init(void)
{
    rt_err_t result;
    
    /* Get configuration pointer */
    log_config = &g_system_config.log;
    
    /* Create log mutex */
    log_mutex = rt_mutex_create("log_mutex", RT_IPC_FLAG_FIFO);
    if (log_mutex == RT_NULL) {
        LOG_E("Failed to create log mutex\n");
        return RT_ERR_MEM;
    }
    
    /* Initialize log buffer */
    rt_memset(log_buffer, 0, sizeof(log_buffer));
    
    /* Try to load existing logs from EEPROM */
    log_load_from_eeprom();
    
    /* Create log thread */
    log_thread = rt_thread_create("log", 
                                 log_thread_entry, 
                                 RT_NULL, 
                                 2048, 
                                 18, 
                                 20);
    if (log_thread == RT_NULL) {
        LOG_E("Failed to create log thread\n");
        rt_mutex_delete(log_mutex);
        return RT_ERR_MEM;
    }
    
    LOG_I("Log module initialized successfully\n");
    return RT_OK;
}

void log_thread_entry(void *parameter)
{
    rt_uint32_t last_storage_time = rt_tick_get();
    message_t msg;
    
    while (1) {
        /* Check if it's time to store logs to EEPROM */
        if (log_config->enable_storage) {
            uint32_t current_time = rt_tick_get();
            if (current_time - last_storage_time >= log_config->storage_interval) {
                log_store_to_eeprom();
                last_storage_time = current_time;
            }
        }
        
        /* Process log messages */
        if (rt_mq_recv(g_msg_queue, &msg, sizeof(msg), 10) == RT_EOK) {
            if (msg.dst_module == MODULE_LOG) {
                process_log_message(&msg);
            }
        }
        
        rt_thread_mdelay(100);
    }
}

rt_err_t log_write(log_level_t level, module_id_t module, const char *message, float data_value)
{
    log_entry_t entry;
    uint32_t index;
    
    if (message == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    /* Acquire log mutex */
    if (rt_mutex_take(log_mutex, RT_WAITING_FOREVER) != RT_EOK) {
        return RT_ERR_BUSY;
    }
    
    /* Prepare log entry */
    entry.level = level;
    entry.timestamp = rt_tick_get();
    entry.module = module;
    entry.event_id = 0;
    entry.data_value = data_value;
    rt_strncpy(entry.message, message, sizeof(entry.message) - 1);
    entry.message[sizeof(entry.message) - 1] = '\0';
    
    /* Determine storage index */
    if (log_config->wrap_around) {
        index = log_config->current_index % log_buffer_size;
    } else {
        index = log_config->current_index;
        if (index >= log_buffer_size) {
            /* Buffer full, start wrapping */
            log_config->wrap_around = RT_TRUE;
            index = 0;
        }
    }
    
    /* Store entry */
    log_buffer[index] = entry;
    log_config->current_index++;
    
    /* Output to console if enabled */
    if (log_config->enable_console) {
        rt_kprintf("[%s/%s] %s (data=%.2f)\n", 
                  log_level_strings[level], 
                  module_strings[module],
                  message, 
                  data_value);
    }
    
    /* Release mutex */
    rt_mutex_release(log_mutex);
    
    return RT_OK;
}

rt_err_t log_read(uint32_t index, log_entry_t *entry)
{
    if (entry == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    if (index >= log_buffer_size) {
        return RT_ERR_PARAM;
    }
    
    /* Acquire log mutex */
    if (rt_mutex_take(log_mutex, RT_WAITING_FOREVER) != RT_EOK) {
        return RT_ERR_BUSY;
    }
    
    /* Copy entry */
    *entry = log_buffer[index];
    
    /* Release mutex */
    rt_mutex_release(log_mutex);
    
    return RT_OK;
}

rt_err_t log_clear(void)
{
    /* Acquire log mutex */
    if (rt_mutex_take(log_mutex, RT_WAITING_FOREVER) != RT_EOK) {
        return RT_ERR_BUSY;
    }
    
    /* Clear buffer */
    rt_memset(log_buffer, 0, sizeof(log_buffer));
    log_config->current_index = 0;
    log_config->wrap_around = RT_FALSE;
    
    /* Clear EEPROM storage */
    eeprom_write(0x1000, (uint8_t*)log_buffer, log_buffer_size * sizeof(log_entry_t));
    
    /* Release mutex */
    rt_mutex_release(log_mutex);
    
    LOG_I("Log cleared\n");
    
    return RT_OK;
}

uint32_t log_get_count(void)
{
    return log_config->current_index;
}

rt_err_t log_set_storage_interval(uint32_t interval)
{
    if (log_config == RT_NULL) {
        return RT_ERR_PARAM;
    }
    
    log_config->storage_interval = interval;
    
    return RT_OK;
}

log_config_t *log_get_config(void)
{
    return log_config;
}